/**
 * 检验是否base64格式
 * @param {*} str 
 * @returns boolean
 */
export function isBase64(str) {
    if (str === '' || str.trim() === '') {
        return false;
    }
    try {
        return btoa(atob(str)) == str;
    } catch (err) {
        return false;
    }
}
/**
* url转base64
* @param {String} url - url地址
*/
export function getImageBase64Data(imgSrc) {

    function getBase64(img) {

        let canvas = document.createElement("canvas");

        canvas.width = img.width;

        canvas.height = img.height;

        let ctx = canvas.getContext("2d");

        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

        let dataURL = canvas.toDataURL('image/jpeg');

        return dataURL;

    }

    let baseUrl = new Promise(function (resolve, reject) {

        let image = new Image();
        image.crossOrigin = 'Anonymous'; // 图片处理跨域
        image.src = `${imgSrc}?v=${new Date()}`;

        image.onload = function () {

            let imageBase64Data = getBase64(image);
            resolve(imageBase64Data);

        }

    });

    return baseUrl;

}
const getValueTypeNumberKeys = (data) => {
    const arr = []
    data.forEach(item => {
        if (item.hasOwnProperty('valueType') && item.valueType === 'number') {
            arr.push(item.prop)
        }
        if (item.hasOwnProperty('children')) {
            arr.push(...getValueTypeNumberKeys(item.children))
        }
    })
    return arr
}
/**
 * @description 创建导出的table表格html（包含图片处理）
 * @param {object[]} tHead 表头数据
 * @param {object[]} tData 表格内容数据 
 * @returns {string} 返回表格的html字符串
 */
export const createTable = (tHead, tData, fileName, merge, mergeProp) => {
    let tH = '<thead >',

        tB = '', //表头和表格体
        arr = [] //表头字段集合
    // 遍历数据生成表头
    arr = getHeadProp(tHead)
    arr = flatten(arr)
    const valueTypeNumberKeys = getValueTypeNumberKeys(tHead)
    console.log(valueTypeNumberKeys, 'valueTypeNumberKeys');
    let thData = columnsHandle(tHead)

    thData.forEach((items, index) => {
        tH += `<tr style="height:100px">`
        items.forEach(item => {
            tH += `<th   style="border:.5px solid #c3cbdd;" rowspan="${!item.key ? 1 : thData.length - index}" colspan="${item.colspan}">${item.title}</th>`
        })
        tH += `</tr>`
    })
    tH += '</thead >'
    let mergeSpan = []
    if (merge) {
        mergeSpan = mergeTableRowSpan(tData, mergeProp, mergeSpan)
    }
    tData.forEach((item, index) => {
        if (index === 0) {
            tB += '<tbody>'
        }
        tB += `<tr style="${arr.includes('base64') ? 'height:200px' : 'height:80px'}" >`
        arr.forEach((td, arrIndex) => {
            if (td === 'base64') {
                tB += ` <td style="width:200px;height:200px; text-align: center; vertical-align: middle;border:.5px solid #c3cbdd;font-size:14px;background-color:${item['row_bgColor']};">
                                <div  style="width:100px;height:10px; text-align: center; vertical-align: middle;padding:50px">
                                  <img src="${item.base64}" width="150" height="150" style="margin:50px">
                                </div>
                            </td>`
            } else {
                if (merge) {
                    if (mergeSpan[td][index] > 0) {
                        tB += `<td  rowspan="${mergeSpan[td][index]}"  style="${valueTypeNumberKeys.includes(td) ? '' : 'mso-number-format:\\@;'}text-align:center;border:2px solid #000;font-size:14px;background-color:${item['row_bgColor']};">${(item[td] === '' || item[td] === null || item[td] === undefined) ? ' ' : item[td]}</td>`
                    }
                } else {
                    tB += `<td   style="${valueTypeNumberKeys.includes(td) ? '' : 'mso-number-format:\\@;'}text-align:center;border:.5px solid #c3cbdd;font-size:14px;background-color:${item['row_bgColor']};">${(item[td] === '' || item[td] === null || item[td] === undefined) ? ' ' : item[td]}</td>`

                }

            }
        })
        tB += '</tr>'
        if (index === tHead.length - 1) {
            tB += '</tbody>'
        }
    })
    if (tData.length === 0) tB = '<tbody></tbody>'
    return tH + tB

}
/**
 * @desc 表格导出
 * @param {object[]} tHead 表头数据
 * @param {object[]} tData 表格内容数据 
 * @param {string} fileName 导出的文件名称 
 */
export function exportTable(tHead, tData, fileName = '列表导出') {
    let html = '<table>' + createTable(tHead, tData, fileName) + '</table>'
    let uri = 'data:application/vnd.ms-excel;base64,',
        template = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
        <head>
        <meta charset="UTF-8">
        <!--[if gte mso 9]>
        <xml>
        <x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>
        {worksheet}
        </x:Name>
        <x:WorksheetOptions>
        <x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>${html}</body></html>`
    //创建下载
    let link = document.createElement('a');
    link.setAttribute('href', uri + window.btoa(unescape(encodeURIComponent(template))));
    link.setAttribute('download', fileName+'.xlsx');
    link.click();
}
export function exportTableModal(html, fileName = '列表导出') {
    let uri = 'data:application/vnd.ms-excel;base64,',
        template = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
        <head>
        <meta charset="UTF-8">
        <!--[if gte mso 9]>
        <xml>
        <x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>
        {worksheet}
        </x:Name>
        <x:WorksheetOptions>
        <x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>${html}</body></html>`
    //创建下载
    let link = document.createElement('a');
    link.setAttribute('href', uri + window.btoa(unescape(encodeURIComponent(template))));
    link.setAttribute('download', fileName);
    link.click();
}
/**
 * @description 导出表格,包含图片,sheet分页
 * @param {String}  fileName 导出的文件名称
 * @param {{prop:String,title:String}[]}  tH_data 表头数据
 * @param {Object[]}  tB_data 表格数据
 * @param {Boolean}  isSheet 是否拆分sheet页
 * @param {Number}  sheetSize sheet页数据量
 * @param {Boolean}  merge 是否合并单元格
 * @param {String[]}  mergeProp 是否合并单元格
 * 
 * @returns function
 */
export function exportSheetTable({ fileName = '无名列表', tH_data = [], tB_data = [], isSheet = false, sheetSize = 5000, merge = false, mergeProp = [] } = {}) {
    var uri = 'data:application/vnd.ms-excel;base64,'
        , html_start = `<html  xmlns:v="urn:schemas-microsoft-com:vml"  xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">`
        , template_ExcelWorksheet = `<x:ExcelWorksheet><x:Name>{SheetName}</x:Name><x:WorksheetSource HRef="sheet{SheetIndex}.htm"/></x:ExcelWorksheet>`
        , template_ListWorksheet = `<o:File HRef="sheet{SheetIndex}.htm"/>`
        , template_HTMLWorksheet = `
------=_NextPart_dummy
Content-Location: sheet{SheetIndex}.htm
Content-Type: text/html; charset=windows-1252
 
` + html_start + `
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link id="Main-File" rel="Main-File" href="../WorkBook.htm">
  <link rel="File-List" href="filelist.xml">
  <style type="text/css">
   table td,table th {
   border: .5px solid #ddd;
   min-height: 40px;
   line-height:40px;
   padding-left:5px;
   padding-right:5px;  
   text-align:center;  
   overflow: hidden;
   font-size:16px;
   padding-top:5px;
   padding-bottom:5px;
   font-family: '微软雅黑';
   width:100%;
  }
  </style>
</head>
<body><table>{SheetContent}</table></body>
</html>`
        , template_WorkBook = `MIME-Version: 1.0
X-Document-Type: Workbook
Content-Type: multipart/related; boundary="----=_NextPart_dummy"
 
------=_NextPart_dummy
Content-Location: WorkBook.htm
Content-Type: text/html; charset=windows-1252
 
` + html_start + `
<head>
<meta name="Excel Workbook Frameset">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="File-List" href="filelist.xml">
<!--[if gte mso 9]><xml>
<x:DisplayGridlines/>
 <x:ExcelWorkbook>
  <x:ExcelWorksheets>{ExcelWorksheets}</x:ExcelWorksheets>
  <x:ActiveSheet>0</x:ActiveSheet>
 </x:ExcelWorkbook>
</xml><![endif]-->
</head>
<frameset>
  <frame src="sheet0.htm" name="frSheet">
  <noframes><body><p>This page uses frames, but your browser does not support them.</p></body></noframes>
</frameset>
</html>
{HTMLWorksheets}
Content-Location: filelist.xml
Content-Type: text/xml; charset="utf-8"
 
<xml xmlns:o="urn:schemas-microsoft-com:office:office">
  <o:MainFile HRef="../WorkBook.htm"/>
  {ListWorksheets}
  <o:File HRef="filelist.xml"/>
</xml>
------=_NextPart_dummy--
`
        , base64 = function (s) { return window.btoa(unescape(encodeURIComponent(s))) }
        , format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) }

    let context_WorkBook = {
        ExcelWorksheets: ''
        , HTMLWorksheets: ''
        , ListWorksheets: ''
    };
    // 是否需要拆分sheet页
    if (isSheet) {

        // 根据sheetSize拆分表格数据 tB_data
        let tbody_Datas = tB_data.reduce((pre, cur, index) => {

            if (index % sheetSize === 0) {
                pre.push([{ ...cur }])
            } else {

                pre[pre.length - 1].push({ ...cur })
            }
            return pre
        }, [])
        if (tbody_Datas.length === 0) tbody_Datas = [[]]
        tbody_Datas.forEach((tables, SheetIndex) => {

            let SheetName = fileName + '(' + (SheetIndex + 1) + ')'
            context_WorkBook.ExcelWorksheets += format(template_ExcelWorksheet, {
                SheetIndex: SheetIndex
                , SheetName: SheetName
            });
            context_WorkBook.HTMLWorksheets += format(template_HTMLWorksheet, {
                SheetIndex: SheetIndex
                , SheetContent: createTable(tH_data, tables, fileName, merge, mergeProp)
            });
            context_WorkBook.ListWorksheets += format(template_ListWorksheet, {
                SheetIndex: SheetIndex
            });
        })
        let link = document.createElement("A");
        link.href = uri + base64(format(template_WorkBook, context_WorkBook));
        link.download = fileName || 'Workbook.xls';
        link.target = '_blank';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    } else {

        exportTable(tH_data, tB_data, fileName)
    }
}
/**
 * 
 * @param {object[]} data 导出的表格数据源
 * @param {string[]} sapnArr 表格中要合并的列字段集合
 * @returns {[]} resArr 表格合并的row集合
 * 
 */
export const mergeTableRowSpan = (data, sapnArr, resArr) => {
    let preKey = ''
    if (data.length === 0) return resArr
    Object.keys(data[0]).forEach((key, keyii) => {
        resArr[key] = []
        if (sapnArr.includes(key)) {
            resArr = merge(key, preKey, keyii, data, resArr)
            preKey = key

        } else {
            resArr[key] = new Array(data.length).fill(1)
        }

    })
    return resArr
}
/**
 * 
 * @param {*} key 
 * @param {*} preKey 
 * @param {*} keyii 
 * @param {*} data 
 * @param {*} resArr 
 * @returns 
 */
export const merge = (key, preKey, keyii, data, resArr) => {
    let position = 0 // 存储要合并的位置
    data.forEach((item, index) => {
        if (index === 0) {
            resArr[key].push(1)
            position = 0
        } else {
            if (preKey && data[index][key] === data[index - 1][key] && resArr[preKey][index] === 0) {
                resArr[key][position] += 1 // 有相同项
                resArr[key].push(0) // 名称相同后往数组里面加一项0
            } else if (!preKey && data[index][key] === data[index - 1][key] && data[index - 1][Object.keys(data[0])[keyii - 1]] === data[index][Object.keys(data[0])[keyii - 1]]) {
                resArr[key][position] += 1 // 有相同项
                resArr[key].push(0) // 名称相同后往数组里面加一项0
            }
            else {
                resArr[key].push(1) // 同列的前后两行单元格不相同
                position = index
            }
        }
    })
    return resArr
}

export const gerMaxCol = (items) => {
    let max = 0;
    function each(data) {
        data.forEach((item) => {
            if (item.children) {
                each(item.children);
            } else {
                max = 1 + max;
            }
        });
    }
    each(items);
    return max;
}
export const getMaxFloor = (treeData) => {
    let max = 0;
    function each(data, floor) {
        data.forEach((e) => {
            if (floor > max) {
                max = floor;
            }
            if (e.children && e.children.length > 0) {
                each(e.children, floor + 1);
            }
        });
    }
    each(treeData, 1);
    return max;
}
export const columnsHandle = (treeData) => {
    let newArr = []

    const maxFloor = 1;
    const keyList = [];
    function each(data, index) {
        if (newArr[index] === undefined) {
            newArr[index] = [];
        }
        data.forEach((e) => {
            const obj = {
                title: e.title,
                key: e.prop,
                rowspan: maxFloor,
                colspan: 1,
                valueType: e.valueType
            };
            if (e.children) {
                obj.colspan = gerMaxCol(e.children);
                obj.rowspan = maxFloor - getMaxFloor(e.children);
            } else {
                if (e.hasrowspan) {             //  如果存在hasrowspan属性并且值为true，则表明该key列存在跨行
                }
            }
            newArr[index].push(obj);
            if (e.children && e.children.length > 0) {
                each(e.children, index + 1);
            }
        });
        return newArr
    }
    return each(treeData, 0);
}
function getHeadProp(data) {
    return data.map(item => {
        if (item.prop) {
            return item.prop
        } else {
            return getHeadProp(item.children)
        }
    })
}
/**
 * @description 嵌套的数组展开平铺
 */
function flatten(arr) {
    return arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
}